import { Injectable, Inject, NotFoundException, BadRequestException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ConfigService } from '@nestjs/config';
import { createReadStream, createWriteStream, existsSync, mkdirSync } from 'fs';
import { join } from 'path';
import { v4 as uuidv4 } from 'uuid';
import * as mime from 'mime-types';
import { BaseService } from '../../../common/services/base.service';
import { File } from '../entities/file.entity';
import { User } from '../../user/entities/user.entity';
import { CreateFileDto } from '../dto/create-file.dto';
import { UpdateFileDto } from '../dto/update-file.dto';
import { QueryFileDto } from '../dto/query-file.dto';
import { PaginationResponseDto } from '../../../common/dto/pagination.dto';
import { FastifyFile } from '../../../common/types/file.types';
import { UserLogService } from '../../user-log/services/user-log.service';

@Injectable()
export class FileService extends BaseService<File> {
  constructor(
    @InjectRepository(File)
    protected readonly fileRepository: Repository<File>,
    private readonly configService: ConfigService,
    private readonly userLogService: UserLogService,
  ) {
    super(fileRepository);
  }

  /**
   * 获取资源类型名称
   */
  public getResourceType(): string {
    return 'file';
  }

  /**
   * 获取资源名称
   */
  public getResourceName(): string {
    return '文件';
  }

  /**
   * 记录创建日志
   */
  public async logCreate(userId?: string, resourceId?: string): Promise<void> {
    if (!userId || !resourceId) return;
    
    try {
      const currentUser = await this.fileRepository.manager.getRepository(User).findOne({ where: { id: userId } });
      if (currentUser) {
        await this.userLogService.logUserAction({
          userId,
          username: currentUser.username,
          actionType: 'create' as any,
          actionDescription: '上传文件',
          resourceType: 'file',
          resourceId,
        });
      }
    } catch (error) {
      // 记录日志失败不影响主流程
      console.error('记录文件创建日志失败', error);
    }
  }

  /**
   * 记录更新日志
   */
  public async logUpdate(userId?: string, resourceId?: string): Promise<void> {
    if (!userId || !resourceId) return;
    
    try {
      const currentUser = await this.fileRepository.manager.getRepository(User).findOne({ where: { id: userId } });
      if (currentUser) {
        await this.userLogService.logUserAction({
          userId,
          username: currentUser.username,
          actionType: 'update' as any,
          actionDescription: '更新文件信息',
          resourceType: 'file',
          resourceId,
        });
      }
    } catch (error) {
      console.error('记录文件更新日志失败', error);
    }
  }

  /**
   * 记录删除日志
   */
  public async logDelete(userId?: string, resourceId?: string): Promise<void> {
    if (!userId || !resourceId) return;
    
    try {
      const currentUser = await this.fileRepository.manager.getRepository(User).findOne({ where: { id: userId } });
      if (currentUser) {
        await this.userLogService.logUserAction({
          userId,
          username: currentUser.username,
          actionType: 'delete' as any,
          actionDescription: '删除文件',
          resourceType: 'file',
          resourceId,
        });
      }
    } catch (error) {
      console.error('记录文件删除日志失败', error);
    }
  }

  /**
   * 上传文件
   */
  async upload(file: FastifyFile, createFileDto: CreateFileDto, user: any): Promise<File> {
    // 验证文件
    this.validateFile(file);

    // 生成唯一文件名
    const fileExtension = file.originalname.split('.').pop();
    const fileName = `${uuidv4()}.${fileExtension}`;
    
    // 获取存储路径
    const uploadPath = this.getUploadPath();
    const filePath = join(uploadPath, fileName);

    // 确保存储目录存在
    if (!existsSync(uploadPath)) {
      mkdirSync(uploadPath, { recursive: true });
    }

    // 保存文件到磁盘
    const writeStream = createWriteStream(filePath);
    writeStream.write(file.buffer);
    writeStream.end();

    // 创建文件记录
    const fileEntity = this.fileRepository.create({
      originalName: file.originalname,
      fileName,
      filePath,
      fileSize: file.size,
      mimeType: file.mimetype,
      fileExtension,
      uploadType: 'local',
      isPublic: createFileDto.isPublic || false,
      uploaderId: user.id,
      description: createFileDto.description,
      tags: createFileDto.tags,
    });

    return await this.fileRepository.save(fileEntity);
  }

  /**
   * 验证文件
   */
  private validateFile(file: FastifyFile): void {
    if (!file) {
      throw new BadRequestException('文件不能为空');
    }

    // 检查文件大小
    const maxSize = this.configService.get<number>('upload.maxSize', 10 * 1024 * 1024);
    if (file.size > maxSize) {
      throw new BadRequestException(`文件大小不能超过 ${maxSize / 1024 / 1024}MB`);
    }

    // 检查MIME类型
    const allowedMimeTypes = this.configService.get<string[]>('upload.allowedMimeTypes', []);
    if (allowedMimeTypes.length > 0 && !allowedMimeTypes.includes(file.mimetype)) {
      throw new BadRequestException('不支持的文件类型');
    }
  }

  /**
   * 获取上传路径
   */
  private getUploadPath(): string {
    const storageConfig = this.configService.get<any>('upload.storage');
    return storageConfig?.local?.path || './uploads';
  }

  /**
   * 下载文件
   */
  async download(id: string): Promise<{ filePath: string; originalName: string; mimeType: string }> {
    const file = await this.findById(id);
    
    // 增加下载次数
    file.downloadCount += 1;
    await this.fileRepository.save(file);
    
    // 检查文件是否存在
    if (!existsSync(file.filePath)) {
      throw new NotFoundException('文件不存在');
    }
    
    return {
      filePath: file.filePath,
      originalName: file.originalName,
      mimeType: file.mimeType,
    };
  }

  /**
   * 根据ID获取文件信息
   */
  async getFileInfo(id: string): Promise<File> {
    return await this.findById(id);
  }

  /**
   * 获取文件列表
   */
  async getFileList(queryDto: QueryFileDto): Promise<PaginationResponseDto<File>> {
    const { page = 1, pageSize = 10, originalName, isPublic, uploaderId } = queryDto;
    
    const queryBuilder = this.fileRepository.createQueryBuilder('file')
      .where('file.isDeleted = :isDeleted', { isDeleted: false });
    
    // 添加查询条件
    if (originalName) {
      queryBuilder.andWhere('file.originalName LIKE :originalName', { originalName: `%${originalName}%` });
    }
    
    if (isPublic !== undefined) {
      queryBuilder.andWhere('file.isPublic = :isPublic', { isPublic });
    }
    
    if (uploaderId) {
      queryBuilder.andWhere('file.uploaderId = :uploaderId', { uploaderId });
    }
    
    // 添加排序
    queryBuilder.orderBy('file.createdAt', 'DESC');
    
    // 分页
    queryBuilder.skip((page - 1) * pageSize).take(pageSize);
    
    const [data, total] = await queryBuilder.getManyAndCount();
    
    return {
      data,
      total,
      page,
      pageSize,
      totalPages: Math.ceil(total / pageSize),
      hasNext: page < Math.ceil(total / pageSize),
      hasPrev: page > 1,
    };
  }

  /**
   * 更新文件信息
   */
  async updateFileInfo(id: string, updateFileDto: UpdateFileDto, user: any): Promise<File> {
    const file = await this.findById(id);
    
    // 检查权限（只有上传者或管理员可以更新）
    if (file.uploaderId !== user.id) {
      throw new BadRequestException('没有权限更新此文件');
    }
    
    // 更新文件信息
    Object.assign(file, updateFileDto);
    return await this.fileRepository.save(file);
  }

  /**
   * 删除文件
   */
  async deleteFile(id: string, user: any): Promise<boolean> {
    const file = await this.findById(id);
    
    // 检查权限（只有上传者或管理员可以删除）
    if (file.uploaderId !== user.id) {
      throw new BadRequestException('没有权限删除此文件');
    }
    
    // 删除磁盘上的文件
    if (existsSync(file.filePath)) {
      require('fs').unlinkSync(file.filePath);
    }
    
    // 软删除数据库记录
    return await this.delete(id);
  }

  /**
   * 获取公开文件列表
   */
  async getPublicFiles(queryDto: QueryFileDto): Promise<PaginationResponseDto<File>> {
    queryDto.isPublic = true;
    return await this.getFileList(queryDto);
  }
}
